package jmine.tec.security.josso.gateway.store;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.josso.auth.Credential;
import org.josso.auth.CredentialKey;
import org.josso.auth.CredentialProvider;
import org.josso.gateway.SSONameValuePair;
import org.josso.gateway.event.SSOEvent;
import org.josso.gateway.event.SSOEventListener;
import org.josso.gateway.event.security.SSOIdentityEvent;
import org.josso.gateway.identity.exceptions.NoSuchUserException;
import org.josso.gateway.identity.exceptions.SSOIdentityException;
import org.josso.gateway.identity.service.BaseRole;
import org.josso.gateway.identity.service.BaseUser;
import org.josso.gateway.identity.service.BaseUserImpl;
import org.josso.gateway.identity.service.store.AbstractStore;
import org.josso.gateway.identity.service.store.ExtendedIdentityStore;
import org.josso.gateway.identity.service.store.SimpleUserKey;
import org.josso.gateway.identity.service.store.UserKey;
import org.josso.selfservices.ChallengeResponseCredential;

/**
 * Extende de {@link AbstractStore} e {@link ExtendedIdentityStore} mas precisa
 * 
 * @author takeshi
 */
public class BasicCredentialStore extends AbstractStore implements ExtendedIdentityStore, SSOEventListener {
    private static final Log LOGGER = LogFactory.getLog(BasicCredentialStore.class);

    private Map<String, BaseUser> usersMapping = new HashMap<String, BaseUser>();

    private Map<String, BaseRole[]> rolesMapping = new HashMap<String, BaseRole[]>();

    /**
     * {@inheritDoc}
     */
    public String loadUsernameByRelayCredential(ChallengeResponseCredential cred) throws SSOIdentityException {
        for (BaseUser user : getUsersMapping()) {
            SSONameValuePair[] props = user.getProperties();
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Checking user : " + user.getName() + " with " + props.length + " properties.");
            }
            if (props == null) {
                continue;
            }
            for (SSONameValuePair prop : props) {
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("Checking property : " + prop.getName() + "=[" + prop.getValue() + "]");
                }
                if (prop.getName().equals(cred.getId()) && prop.getValue().equals(cred.getResponse())) {
                    return user.getName();
                }
            }
        }
        return null;
    }

    /**
     * @return {@link Collection} de {@link BaseUser}
     */
    private synchronized Collection<? extends BaseUser> getUsersMapping() {
        return new ArrayList<BaseUser>(this.usersMapping.values());
    }

    /**
     * {@inheritDoc}
     */
    public void updateAccountPassword(UserKey arg0, Credential arg1) throws SSOIdentityException {
        throw new RuntimeException("cannot updateAccountPassword");
    }

    /**
     * {@inheritDoc}
     */
    public synchronized BaseRole[] findRolesByUserKey(UserKey arg0) throws SSOIdentityException {
        String name = ((SimpleUserKey) arg0).getId();
        BaseRole[] baseRoles = rolesMapping.get(name);
        if (baseRoles == null) {
            return new BaseRole[]{};
        }
        return baseRoles;
    }

    /**
     * {@inheritDoc}
     */
    public BaseUser loadUser(UserKey arg0) throws NoSuchUserException, SSOIdentityException {
        String name = ((SimpleUserKey) arg0).getId();
        return this.usersMapping.get(name);
    }

    /**
     * {@inheritDoc}
     */
    public Credential[] loadCredentials(CredentialKey arg0, CredentialProvider arg1) throws SSOIdentityException {
        return new Credential[]{};
    }

    /**
     * {@inheritDoc}
     */
    public String loadUID(CredentialKey arg0, CredentialProvider arg1) throws SSOIdentityException {
        if (!(arg0 instanceof SimpleUserKey)) {
            throw new SSOIdentityException("Unsupported key type : " + arg0.getClass().getName());
        }
        SimpleUserKey simpleKey = (SimpleUserKey) arg0;
        return simpleKey.getId();
    }

    /**
     * @param baseUser the {@link BaseUser}
     * @param roles the roles to assign
     */
    public synchronized void put(BaseUserImpl baseUser, BaseRole[] roles) {
        this.rolesMapping.put(baseUser.getName(), roles);
        this.usersMapping.put(baseUser.getName(), baseUser);
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.josso.gateway.event.SSOEventListener#getName()
     */
    public String getName() {
        return "basicCredentialStore";
    }

    /**
     * {@inheritDoc}
     */
    public void handleSSOEvent(SSOEvent event) {
        if (event.getType().equals(SSOIdentityEvent.LOGOUT_SUCCESS_EVENT) || event.getType().equals(SSOIdentityEvent.LOGOUT_FAILED_EVENT)) {
            String userName = ((SSOIdentityEvent) event).getUsername();
            synchronized (this) {
                rolesMapping.remove(userName);
                usersMapping.remove(userName);
            }
        }
    }

}
